package org.apache.commons.tfs;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LicenceFactory {
    
    private static final char SEPERATOR = '~';
    
    private static final SimpleDateFormat DATE_FOMAT = new SimpleDateFormat("yyyyMMdd");
    
    private static final String KEY_LICENCE = "Licence";
    
    private static final String KEY_KEY = "Key";
    
    private static final String PRIVATE_KEY = "rs2UYchhSYU=";
    
    private static final String LICENCE_FILE = "/licence.properties";
    
    private static final byte[] PUBLIC_KEY = ("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjICVNTUNarL+eHZ1IDCAWAX/oEfMktdLSp5XP" + "+REvVWMO8ZTnuM4Pddh819D97EtPIrivIYNsxCTJPQt7+ldfaJnEtImRq1iXLlPRuFqAiU2dVkS2"
                                              + "uFvcCEnrffBav/RDazod0bC4Oa77nSdRJlxCcyBUKeTsV65Qls3clbe/XQIDAQAB").getBytes();
    
    private static final Log logger = LogFactory.getLog(LicenceFactory.class);
    
    public static class LicenceFactoryHolder {
        public static LicenceFactory instance = new LicenceFactory();
    }
    
    public static LicenceFactory getInstance() {
        return LicenceFactoryHolder.instance;
    }
    
    private Licence licence;
    
    private LicenceFactory() {
        load();
    }
    
    private void load() throws LicenseException {
        Properties properties = new Properties();
        InputStream is = LicenceFactory.class.getResourceAsStream(LICENCE_FILE);
        try {
            properties.load(is);
        }
        catch (Exception e) {
            throw new LicenseException(Licence.MSG_NOT_FOUND);
        }
        
        String key = properties.getProperty(KEY_KEY);
        String licenceStr = properties.getProperty(KEY_LICENCE);
        if (key == null || licenceStr == null) {
            throw new LicenseException(Licence.MSG_UNVALID);
        }
        if (!SignProvider.verify(PUBLIC_KEY, key, licenceStr.getBytes())) {
            throw new LicenseException(Licence.MSG_UNVALID);
        }
        
        try {
            key = DesUtils.decrypt(key, PRIVATE_KEY);
        }
        catch (Exception e) {
            throw new LicenseException(Licence.MSG_UNVALID);
        }
        
        DefaultLicence licence = null;
        try {
            // String[] setions = key.split(String.valueOf(SEPERATOR));
            String[] setions = split(key, SEPERATOR);
            licence = new DefaultLicence();
            licence.setName(setions[0]);
            licence.setCode(setions[1]);
            licence.setVersion(setions[2]);
            
            String versionTypeStr = setions[3];
            VersionType versionType = null;
            try {
                versionType = VersionType.valueOf(versionTypeStr);
            }
            catch (Exception e) {
            }
            if (versionType == null) {
                versionType = VersionType.Unknown;
            }
            licence.setVersionType(versionType);
            
            licence.setCopyright(setions[4]);
            licence.setSign(toDate(setions[5]));
            licence.setUnit(setions[6]);
            licence.setExpiry(toDate(setions[7]));
            licence.setUserLimit(Integer.parseInt(setions[8]));
            licence.setBoard(setions[9]);
            licence.setCpus(setions[10]);
            licence.setDisks(setions[11]);
            licence.setMacs(setions[12]);
        }
        catch (Exception e) {
            throw new LicenseException(Licence.MSG_UNVALID, e);
        }
        
        this.licence = licence;
    }
    
    private Date toDate(String str) throws Exception {
        if (str == null || str.length() == 0) {
            return null;
        }
        return DATE_FOMAT.parse(str);
    }
    
    public Licence getLicence() {
        return licence;
    }
    
    private String[] split(String str, char seperator) {
        if (logger.isDebugEnabled()) {
            logger.debug("Before splite=" + str);
        }
        
        if (str == null) {
            return null;
        }
        
        if (str.length() == 0) {
            return new String[] { str };
        }
        
        List<Integer> pos = new ArrayList<Integer>();
        for (int i = 0; i < str.length(); i++) {
            if (seperator == str.charAt(i)) {
                pos.add(i);
            }
        }
        
        if (pos.isEmpty()) {
            return new String[] { str };
        }
        
        String[] setions = new String[pos.size() + 1];
        int start = 0;
        for (int i = 0; i < pos.size(); i++) {
            int end = pos.get(i);
            setions[i] = str.substring(start, end);
            start = end + 1;
            if (logger.isDebugEnabled()) {
                logger.debug("setions[" + i + "]=" + setions[i]);
            }
        }
        setions[setions.length - 1] = str.substring(start);
        if (logger.isDebugEnabled()) {
            logger.debug("setions[" + (setions.length - 1)
                         + "]="
                         + setions[setions.length - 1]);
        }
        
        return setions;
    }
}
